﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Web.Resources;
using System.Globalization;
using System.Web.Mvc;
using System.Web.UI;

namespace MvcImproved.Generic.Controls
{
	public abstract class GenericInputControl<TDataItem, TMemberValue> : NamedGenericControl<TDataItem, TMemberValue>
	{
		string InputType;
		protected Boolean RenderChildrenFirst;

		public string CssClass
		{ get; set; }

		public bool HideClientId
		{ get; set; }


		public bool Disabled
		{ get; set; }

		public string Label
		{ get; set; }

		protected GenericInputControl(Func<TDataItem, TMemberValue> valueMember, string inputType)
			: base(valueMember)
		{
			InputType = inputType;
		}

		protected ModelState GetModelState()
		{
			return ViewData.ModelState[Name];
		}

		protected object GetModelStateValue(string key, Type destinationType)
		{
			ModelState modelState = GetModelState();
			if (modelState != null)
			{
				try
				{
					return modelState.Value.ConvertTo(destinationType, null /* culture */);
				}
				catch (InvalidOperationException e)
				{
					return null;
				}
			}
			return null;
		}

		protected abstract void ControlSpecificRender(HtmlTextWriter writer, SortedDictionary<string, string> attrs);

		protected override void Render(HtmlTextWriter writer)
		{
			bool wrapWithLabel = (Label != null) || HasControls();
			
			if (wrapWithLabel)
				writer.RenderBeginTag(HtmlTextWriterTag.Label);

			if (RenderChildrenFirst)
				base.Render(writer);

			if (String.IsNullOrEmpty(Name))
				throw new InvalidOperationException("Name Required");

			SortedDictionary<string, string> attrs = new SortedDictionary<string, string>();

			foreach (KeyValuePair<string, string> attribute in Attributes)
			{
				attrs.Add(attribute.Key, attribute.Value);
			}

			if (!Attributes.ContainsKey("type"))
			{
				attrs.Add("type", InputType);
			}
			attrs.Add("name", Name);
			if (!String.IsNullOrEmpty(ClientID) && (! HideClientId))
			{
				attrs.Add("id", ClientID);
			}

			ControlSpecificRender(writer, attrs);

			string cssClass;
			if (!attrs.TryGetValue("class", out cssClass) && (! String.IsNullOrEmpty(cssClass)))
				attrs["class"] = CssClass;

			if (Disabled)
				attrs["disabled"] = "disabled";

			if (!DesignMode)
			{
				// If there are any errors for a named field, we add the CSS attribute.
				ModelState modelState = GetModelState();
				if ((modelState != null) && (modelState.Errors.Count > 0))
				{
					string currentValue;

					if (attrs.TryGetValue("class", out currentValue))
					{
						attrs["class"] = HtmlHelper.ValidationInputCssClassName + " " + currentValue;
					}
					else
					{
						attrs["class"] = HtmlHelper.ValidationInputCssClassName;
					}
				}
			}

			foreach (KeyValuePair<string, string> attribute in attrs)
			{
				writer.AddAttribute(attribute.Key, Convert.ToString(attribute.Value, CultureInfo.CurrentCulture));
			}

			writer.RenderBeginTag(HtmlTextWriterTag.Input);

			writer.RenderEndTag();

			if (! RenderChildrenFirst)
				base.Render(writer);

			if (wrapWithLabel)
			{
				if (Label != null)
					writer.Write(Label);
				writer.RenderEndTag();
			}
		}
	}
}
